<template>
  <div ref="done" class="border-1 border-white border-solid1 flex w-full justify-center text-gray-300">
    <ul v-if="!pipelineDone" class="w-full flex flex-col items-center">
      <li
        v-for="step in steps.filter((step) => step.show)"
        :key="step.name"
        class="min-w-[calc(1.875rem*14)] flex items-center py-2 text-3xl space-x-3 animate-fade-in-up animate-duration-300"
      >
        <span>{{ step.done ? step.doneText : step.loadingText }}</span>
        <transition name="icon-loading" mode="out-in">
          <span v-if="step.loading" class="i-mdi:loading animate-spin text-4xl"></span>
          <span v-else class="i-mdi:check-circle text-green-500 align-mid text-4xl -mt-1 animate-tada"></span>
        </transition>
      </li>
    </ul>
    <a-result
      v-else
      status="success"
      class="animate-light-speed-in-right animate-duration-400"
      @vue:mounted="expandSvgIcon"
    >
      <template #title>
        <h1 class="text-5xl mt-10 tracking-wider">项目初始化成功!</h1>
      </template>
      <template #extra>
        <a-button
          key="console"
          type="primary"
          class="animate__animated h-[2.5rem] text-[1.5rem] focus-visible:bg-green-200"
          :loading="false"
          @mousedown="animatify"
        >
          开始构建页面
        </a-button>
      </template>
    </a-result>
  </div>
</template>

<script setup lang="ts" name="init-done">
import useTranslate from '@/hooks/useTranslate'
import { message } from 'ant-design-vue'
import { baseWalk, whitespace2kebab } from '@/utils/tool'
import { useGlobalStore } from '@/store'

import { TransitionPresets, useTransition } from '@vueuse/core'
import { useCreateDirectory, usePathExist, useWriteFile } from '@/hooks/useFile'
import useMinWaitPromise from '@/hooks/useMinWaitPromise'

interface StateGroup {
  show: boolean
  name: string
  loading: boolean
  loadingText: string
  percent: number
  done: boolean
  doneText: string
  transitionRef: ComputedRef<number>
  next: StateGroup | null
}

type StepConf = Pick<StateGroup, 'name' | 'loadingText' | 'doneText'>

const pipelineDone = ref(false)

const mixRest = (conf: StepConf): StateGroup => {
  const states = reactive({
    ...conf,
    show: false,
    loading: false,
    done: false,
    percent: 0
  }) as Exclude<StateGroup, 'transitionRef'>

  const integrated: StateGroup = Object.assign(states, {
    transitionRef: useTransition(() => states.percent, {
      duration: 500,
      transition: TransitionPresets.easeInOutCubic
    })
  })

  return integrated
}

const step_translate = mixRest({
  name: 'translate',
  loadingText: '正在获取菜单项翻译',
  doneText: '已获取菜单项翻译'
})
const step_createDir = mixRest({
  name: 'createDir',
  loadingText: '正在创建菜单项对应目录',
  doneText: `菜单项目录已创建`
})

const steps = [step_translate, step_createDir]
const stepMap = steps.reduce(
  (map, step) => {
    map[step.name] = step
    return map
  },
  Object.create(null) as Record<string, StateGroup>
)

const getTranslateTree = async (originData: Menu) => {
  const tree2bTranslate = [...originData]

  let historyTranslate: Record<string, string> = {}
  // 获取历史翻译数据，最小化数据查询
  const { isExist, content } = await usePathExist({
    path: `${store.recordsPath}\\${store.dictionary}`,
    returnText: true
  })
  if (isExist) {
    historyTranslate = JSON.parse(content) as Record<string, string>
  }

  // 去除重复字段
  const translateTexts: Set<string> = new Set()
  baseWalk(tree2bTranslate, ({ label }) => {
    !historyTranslate[label] && translateTexts.add(label)
  })

  const last = Date.now()
  stepMap.translate.show = true
  stepMap.translate.loading = true

  // 首先给菜单项生成英文 kebab 格式的英文，作为目录名称
  let result: { src: string; dst: string }[] = []
  if (translateTexts.size) {
    result = await useTranslate([...translateTexts])
  }

  await useMinWaitPromise(last, null, 800)

  stepMap.translate.loading = false
  stepMap.translate.done = true

  // { src => 原文 ：dst => 译文}
  let translateMap: Record<string, string> = result.reduce((map, { src, dst }) => {
    // 译文可能出现末端多余的空格，以及 ` - ` 字符 => ` `,
    map[`${src}`] = whitespace2kebab(dst.trim().replace(/(\s)-\s/, '$1'))
    return map
  }, Object.create(null))
  translateMap = Object.assign(historyTranslate, translateMap)

  const { error } = await useWriteFile({
    root: store.recordsPath,
    filename: store.dictionary,
    content: translateMap,
    useExport: false
  })
  if (error) throw new Error('存储翻译记录失败')

  baseWalk(tree2bTranslate, (item) => {
    item.translate = translateMap[item.label.replace(/\*/, '')].replace(/-management/, '')
  })

  return tree2bTranslate
}

const store = useGlobalStore()
const pipeline = async () => {
  try {
    const translateTree = await getTranslateTree(store.treeToTranslate)
    store.treeToTranslate = translateTree

    stepMap.createDir.show = true
    stepMap.createDir.loading = true

    // 生成需要创建的文件夹，并给菜单项设置文件存储路径
    const getPath = (tree: Menu, parentPath: string): any[] => {
      return tree.map((item) => {
        const path = [parentPath, item.translate.replace(/-management/, '')].filter(Boolean).join('/')
        item.directory = path
        return item.children ? getPath(item.children, path) : path
      })
    }
    const pathsToCreate: string[] = getPath(translateTree, '').flat(Infinity)

    const { error: error1 } = await useCreateDirectory({
      root: store.viewPath,
      paths: pathsToCreate
    })
    if (error1) throw new Error(`创建文件夹出错: ${error1}`)

    const { error: error2 } = await useWriteFile({
      root: store.treePath,
      filename: store.translatedFile,
      content: translateTree,
      useExport: false
    })
    if (error2) throw new Error('存储翻译树数据出错')

    stepMap.createDir.loading = false
    stepMap.createDir.done = true

    await useMinWaitPromise(Date.now(), null, 2400)

    pipelineDone.value = true
  } catch (error: any) {
    console.log(error)

    message.error(`${error?.message || error}`, 5)
  }
}
const emit = defineEmits<{
  (event: 'processing'): void
  (event: 'done'): void
}>()

pipeline()

const done = ref(null) as Ref<HTMLElement | null>

const expandSvgIcon = () => {
  if (done.value) {
    const svgEl = done.value.querySelector('[data-icon="check-circle"]')
    svgEl?.setAttribute('width', '10rem')
    svgEl?.setAttribute('height', '10rem')

    svgEl?.classList.add('animate__animated')

    setTimeout(() => {
      svgEl?.classList.add('animate__rubberBand')
    }, 200)
  }
}

const animatify = () => {
  const buttnEl = done.value?.querySelector('.ant-btn') as HTMLElement
  buttnEl.classList.add('scale-90')

  const handler = () => {
    buttnEl.classList.add('animate__tada')
    buttnEl.onanimationend = () => {
      buttnEl.classList.remove('animate__tada', 'scale-90')
      buttnEl.onanimationend = null

      startup()
    }
    window.removeEventListener('mouseup', handler)
  }
  window.addEventListener('mouseup', handler)
}

const startup = () => {
  emit('processing')

  setTimeout(() => {
    emit('done')
  }, 1000)
}
</script>
